﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;

public class CachePool<T> : ICachePool where T : IPoolObject
{
    public GameObject prefab;
    public Transform parent;

    List<T> cacheItems = new List<T>();
    List<T> freeItems = new List<T>();

    public CachePool(GameObject prefab, Transform parent)
    {
        this.prefab = prefab;
        this.parent = parent;
    }

    public void SetParent(T item, Transform parent)
    {
        item.SetParent(parent);
    }

    /// <summary>
    /// 获得对象
    /// </summary>
    /// <param name="autoTurnOn">自动开启，false则需要外部调用下TurnOn</param>
    /// <returns></returns>
    public T GetOrCreateOne<T1>(bool autoTurnOn = true) where T1 : T
    {
        T result = GetFree();
        if (result == null)
        {
            result = CreateItem<T1>();
            cacheItems.Add(result);
        }
        if (autoTurnOn) result.TurnOn();
        return result;
    }

    /// <summary>
    /// 从index获得对象
    /// </summary>
    /// <param name="index"></param>
    /// <param name="autoTurnOn">自动开启，false则需要外部调用下TurnOn</param>
    /// <returns></returns>
    public T GetOrCreateOne(int index, bool autoTurnOn = true)
    {
        return GetOrCreateOne<T>(index, autoTurnOn);
    }

    /// <summary>
    /// 从index获得对象
    /// </summary>
    /// <param name="index"></param>
    /// <param name="autoTurnOn">自动开启，false则需要外部调用下TurnOn</param>
    /// <returns></returns>
    public T GetOrCreateOne<T1>(int index, bool autoTurnOn = true) where T1 : T
    {
        T result = default(T);
        if (index <= cacheItems.Count - 1)
        {
            result = cacheItems[index];
        }
        else
        {
            result = CreateItem<T1>();
            cacheItems.Add(result);
        }
        if (autoTurnOn) result.TurnOn();
        return result;
    }

    /// <summary>
    /// 从index开始回收
    /// </summary>
    /// <param name="index"></param>
    public void RecycleFrom(int index)
    {
        for (int i = index; i < cacheItems.Count; i++)
        {
            T cacheItem = cacheItems[i];
            if (cacheItem.IsTurnOn)
            {
                cacheItem.TurnOff();
                SetFree(cacheItem);
            }
        }
    }

    /// <summary>
    /// 被回收
    /// </summary>
    /// <param name="item"></param>
    public void RecycleBy(IPoolObject item)
    {
        Recycle((T)item);
    }

    /// <summary>
    /// 被移除
    /// </summary>
    /// <param name="item"></param>
    public void RemoveBy(IPoolObject item)
    {
        Remove((T)item);
    }

    /// <summary>
    /// 回收物体
    /// </summary>
    /// <param name="item"></param>
    public void Recycle(T item)
    {
        if (item == null) return;
        if (item.IsTurnOn)
            item.TurnOff();
        if (!cacheItems.Contains(item))
        {
            cacheItems.Add(item);
        }
        SetFree(item);
    }

    /// <summary>
    /// 移除对象
    /// </summary>
    /// <param name="item"></param>
    public void Remove(T item)
    {
        if (cacheItems.Contains(item))
        {
            cacheItems.Remove(item);
        }
        if (freeItems.Contains(item))
        {
            freeItems.Remove(item);
        }
    }

    /// <summary>
    /// 是否包含对象
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    public bool Contains(T item)
    {
        for (int i = 0; i < cacheItems.Count; i++)
        {
            T cacheItem = cacheItems[i];
            if (cacheItem == null) continue;
            if (cacheItem.Equals(item)) return true;
        }
        return false;
    }

    /// <summary>
    /// 销毁所有
    /// </summary>
    public void DestroyAll()
    {
        for (int i = 0; i < cacheItems.Count; i++)
        {
            T cacheItem = cacheItems[i];
            if (cacheItem != null)
            {
                cacheItem.DestroySelf();
            }
        }
        cacheItems.Clear();
        freeItems.Clear();
    }

    /// <summary>
    /// 释放缓存
    /// </summary>
    public void Release()
    {
        foreach (var poolObject in freeItems)
        {
            if (poolObject != null)
            {
                poolObject.DestroySelf();
            }
        }
        freeItems.Clear();
    }

    T GetFree()
    {
        if (freeItems.Count > 0)
        {
            var freeItem = freeItems[0];
            freeItems.RemoveAt(0);
            return freeItem;
        }
        return default(T);
    }

    void SetFree(T item)
    {
        if (!freeItems.Contains(item))
            freeItems.Add(item);
    }

    T CreateItem<T1>() where T1 : T
    {
        GameObject go = GameObject.Instantiate(prefab, parent);
        T1 result = default(T1);
        if (typeof(T1) == typeof(IPoolObject) || typeof(Object).IsAssignableFrom(typeof(T1)))
        {
            result = go.GetComponent<T1>();
        }
        else
        {
            result = Activator.CreateInstance<T1>();
        }
        result.SetOwner(this);
        result.SetObject(go);
        return result;
    }

    /// <summary>
    /// 当前总数
    /// </summary>
    public int TotalCount
    {
        get { return cacheItems.Count; }
    }

    /// <summary>
    /// 查找元素索引
    /// </summary>
    /// <param name="match"></param>
    /// <returns></returns>
    public int FindIndex(Predicate<T> match)
    {
        return cacheItems.FindIndex(match);
    }

    /// <summary>
    /// 查找元素
    /// </summary>
    /// <param name="match"></param>
    /// <returns></returns>
    public T FindItem(Predicate<T> match)
    {
        return cacheItems.Find(match);
    }

    /// <summary>
    /// 查找所有元素
    /// </summary>
    /// <param name="match"></param>
    /// <returns></returns>
    public List<T> FindItemAll(Predicate<T> match)
    {
        return cacheItems.FindAll(match);
    }
}
